// The obvious piece of programmer art in any OSL intro is a Mandelbrot shader

shader Mandelbrot(
   output color c = 0,
   int maxcount = 100
       [[int min=1, int max=20000, int sliderexponent=4,
          string label = "Max iterations",
          string help = "Maximal amount of iterations (z = z + c)"]],
   int outputScale = 100
       [[int min=1, int max=20000, int sliderexponent=4,
          string label = "Iterations scale factor",
          string help = "Amount of iterations mapped to white"]],
   float gamma = 1.0
       [[float min=0.1, float max=10, int sliderexponent=4,
          string label = "Gamma",
          string help = "Gamma value applied to the gradient"]],
   point projection = 0
        [[string label = "Projection"]],
   matrix xform = matrix(.33333, 0, 0, -.5, 0, .33333, 0, -.33333, 0, 0, .33333, 0, 0, 0, 0, 1)
        [[string label = "UV transform", int dim = 2]],
   int smooth = 0
       [[string widget="checkBox",
          string label = "Smooth gradient",
          string help = "Smooth out the gradient outside the Mandelbrot set"]])
{
    point p = transform(1 / xform, projection);
   float cx = (p[0]-.5);
   float cy = (p[1]-.5);
   float x = cx;
   float y = cy;
   float prevRR = 0;
    float rr = x*x + y*y;
   int count = 0;
   while (rr < 4 && count < maxcount)
   {
      count += 1;
      // z = z + c
      float x2 = x*x - y*y + cx;
      y = 2*x*y + cy;
      x = x2;
      prevRR = rr;
      rr = x*x + y*y;
   }

   if (count < maxcount)
   {
      float h = (float)count;
      if (smooth)
      {
         h = h + (4 - prevRR) / (rr - prevRR);
      }
       c = pow(h / outputScale, gamma);
      c = min(c, .999);
   }
   else
   {
      c = 1.0;
   }
}